/*
 * Player.java
 * 
 * author: The MomberBan Team
 *    date: 12.09.2008
 * 
 * 
 */

package at.momberban2.me.gamecontext;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

import at.momberban2.me.game.M2Event;
import at.momberban2.me.game.M2ResourceManager;
import at.syncme.framework.Entity;
import at.syncme.framework.legacy.WrapperCache;
import de.enough.polish.io.Serializable;

/**
 * a momberban player
 * 
 * @author patchinsky
 */
public class M2Player extends Entity implements Serializable {
    private static transient final M2ResourceManager MGR = (M2ResourceManager) M2ResourceManager
            .getInstance();

    /**
     * player width
     */
    public static final int PLAYER_WIDTH = 21;

    /**
     * player height
     */
    public static final int PLAYER_HEIGHT = 32;

    /**
     * default player speed
     */
    public static final int DEFAULT_SPEED = 4;

    /**
     * default player prefix
     */
    public static final String PLAYER_PREFIX = MGR.getTextFor("playerPrefix");
    
    private static final byte INITIAL_BOMBS = Byte.parseByte(MGR.getCfgFor("initialBombs"));

    private transient Sprite sprite;

    private transient Image preview;

    private byte id, bombs, speed, move, lastPosition, bombRange, bombStock,
            deaths, frags, score;

    private String name;

    private boolean dead;

    /**
     * default constructor
     * 
     * @deprecated
     */
    public M2Player() {
        // only used in serialization
    }

    /**
     * constructor
     * 
     * @param id
     *            the player id
     * @throws IOException
     */
    public M2Player(byte id) {
        loadImages(id);

        this.id = id;
        this.name = PLAYER_PREFIX + id;
        revitalize();

        Timer animation = new Timer();
        animation.schedule(new PlayerAnimationTask(), 0, 100);
    }

    /**
     * load all images
     * 
     * @param Pid
     */
    private void loadImages(int Pid) {
        this.sprite = new Sprite(MGR.loadImage("/images/Player" + Pid + ".png"),
                PLAYER_WIDTH, PLAYER_HEIGHT);
        this.preview = MGR.loadImage("/images/Player" + Pid + ".png", 0, 0,
                PLAYER_WIDTH, PLAYER_HEIGHT, Sprite.TRANS_NONE);
    }

    /**
     * revitalize this player
     */
    public void revitalize() {
        this.bombStock = INITIAL_BOMBS;
        this.bombs = this.bombStock;
        this.bombRange = M2Bomb.DEFAULT_EXPLOSION_RANGE;
        this.dead = false;
        this.speed = DEFAULT_SPEED;
    }
    
    /**
     * return if the player can plant bombs
     * 
     * @return
     */
    public boolean canPlant() {
        // TODO extended by diseases 
        return this.bombs > 0 && !this.dead;
    }

    /**
     * @return sprite
     */
    public Sprite getSprite() {
        return sprite;
    }

    /**
     * @param move
     */
    public void setMove(byte move) {
        this.move = move;
    }

    /**
     * @return move
     */
    public byte getMove() {
        return move;
    }

    /**
     * Getter of the property <tt>speed</tt>
     * 
     * @return Returns the speed.
     */

    public byte getSpeed() {
        return speed;
    }

    /**
     * Setter of the property <tt>speed</tt>
     * 
     * @param speed
     *            The speed to set.
     */
    public void setSpeed(byte speed) {
        this.speed = speed;
    }

    /**
     * Getter of the property <tt>maxBombs</tt>
     * 
     * @return Returns the maxBombs.
     */

    public byte getMaxBombs() {
        return bombStock;
    }

    /**
     * Setter of the property <tt>maxBombs</tt>
     * 
     * @param bombMax
     *            The bombMax to set.
     */
    public void setMaxBombs(byte bombMax) {
        this.bombStock = bombMax;
    }

    /**
     * @return bombs
     */
    public byte getBombs() {
        return bombs;
    }

    /**
     * @param bombs
     *            to set
     */
    public void setBombs(byte bombs) {
        this.bombs = bombs;
    }

    /**
     * @return id
     */
    public byte getId() {
        return id;
    }

    /**
     * @param name
     *            to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * @return preview
     */
    public Image getPreview() {
        return preview;
    }

    /**
     * @return
     */
    public byte getLastPosition() {
        return this.lastPosition;
    }

    /**
     * @param lastPosition
     *            to set
     */
    public void setLastPosition(byte lastPosition) {
        this.lastPosition = lastPosition;
    }

    /**
     * @param bombRange
     *            to set
     */
    public void setBombRange(byte bombRange) {
        this.bombRange = bombRange;
    }

    /**
     * @return bombRange
     */
    public byte getBombRange() {
        return bombRange;
    }

    /**
     * @return deaths
     */
    public int getDeaths() {
        return deaths;
    }

    /**
     * @param deaths
     *            to set
     */
    public void setDeaths(byte deaths) {
        this.deaths = deaths;
    }

    /**
     * @return frags
     */
    public byte getFrags() {
        return frags;
    }

    /**
     * @param frags
     *            to set
     */
    public void setFrags(byte frags) {
        this.frags = frags;
    }

    /**
     * @return dead
     */
    public boolean isDead() {
        return dead;
    }

    /**
     * @param dead
     *            to set
     */
    public void setDead(boolean dead) {
        // TODO Media.playKillSound();
        this.dead = dead;
    }

    /**
     * Animates a player
     * 
     * @author dobby
     * @author patchinsky
     */
    private class PlayerAnimationTask extends TimerTask {

        private byte lastDirection;

        private boolean runAnimation;

        public void run() {
            int frame = sprite.getFrame();
            if (move != this.lastDirection) {
                this.lastDirection = move;
                this.runAnimation = true;
                if (move == M2Event.MOVE_DOWN) {
                    sprite.setFrame(0);
                } else if (move == M2Event.MOVE_LEFT) {
                    sprite.setFrame(4);
                } else if (move == M2Event.MOVE_UP) {
                    sprite.setFrame(8);
                } else if (move == M2Event.MOVE_RIGHT) {
                    sprite.setFrame(12);
                } else if (move == M2Event.MOVE_STOP) {
                    this.runAnimation = false;
                }
            } else if (frame % 4 == 3) {
                sprite.setFrame(frame - 3); // reset
            }

            if (this.runAnimation) {
                sprite.nextFrame();
            }
        }
    }

    /**
     * override
     * 
     * @see at.syncme.framework.Entity#read(java.io.DataInputStream)
     */
    public void read(DataInputStream in) throws IOException {
        this.id = in.readByte();
        this.bombs = in.readByte();
        this.speed  = in.readByte();
        this.move = in.readByte();
        this.lastPosition = in.readByte();
        this.bombRange = in.readByte();
        this.bombStock = in.readByte();
        this.frags = in.readByte();
        this.score = in.readByte();
        this.dead  = in.readBoolean();
        this.name = in.readUTF();
        
        loadImages(this.id);
    }

    /**
     * override
     * 
     * @see at.syncme.framework.Entity#write(java.io.DataOutputStream)
     */
    public void write(DataOutputStream out) throws IOException {
        out.writeByte(this.id);
        out.writeByte(this.bombs);
        out.writeByte(this.speed);
        out.writeByte(this.move);
        out.writeByte(this.lastPosition);
        out.writeByte(this.bombRange);
        out.writeByte(this.bombStock);
        out.writeByte(this.frags);
        out.writeByte(this.score);
        out.writeBoolean(this.dead);
        out.writeUTF(this.name);
    }
    
    /**
     * override
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj) {
        if (obj instanceof M2Player) {
            M2Player comp = (M2Player) obj;
            
            return this.id == comp.getId();
        } else {
            return false;
        }
    }
    
    /**
     * override
     *
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return WrapperCache.valueOf(this.id).hashCode();
    }

    /**
     * i like to move it, move it
     */
    public void move() {
        int newX = this.sprite.getX();
        int newY = this.sprite.getY();

        if (this.move == M2Event.MOVE_DOWN) {
            newY += this.speed;
        } else if (move == M2Event.MOVE_UP) {
            newY -= this.speed;
        } else if (move == M2Event.MOVE_LEFT) {
            newX -= this.speed;
        } else if (move == M2Event.MOVE_RIGHT) {
            newX += this.speed;
        } else {
            // ugly, but powerful ;)
            return;
        }
        
        // commit
        this.sprite.setPosition(newX, newY);
    }
}
